package com.google.code.p.restrpc.core.async.impl;

import java.util.Properties;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import com.google.code.p.restrpc.AsyncRpcResult;
import com.google.code.p.restrpc.core.RpcServiceMetadata;
import com.google.code.p.restrpc.core.RpcServiceRepository;
import com.google.code.p.restrpc.core.async.AsyncRpcRequestProcessedEventObject;
import com.google.code.p.restrpc.core.async.AsyncRpcResultCache;
import com.google.code.p.restrpc.core.async.AsyncRpcResultRetriever;
import com.google.code.p.restrpc.core.async.AsyncServiceManager;
import com.google.code.p.restrpc.core.async.AsyncServiceQueue;
import com.google.code.p.restrpc.core.async.mem.AsyncRpcResultMemCache;
import com.google.code.p.restrpc.core.async.mem.AsyncRpcResultMemCacheOptions;
import com.google.code.p.restrpc.event.RpcEventCenter;
import com.google.code.p.restrpc.event.RpcEventListener;
import com.google.code.p.restrpc.event.RpcEventObject;

/**
 * @author dz
 */
public class DefaultAsyncServiceManager implements
                                       AsyncServiceManager,
                                       RpcEventListener {
    
    private final Log logger = LogFactory.getLog(DefaultAsyncServiceManager.class);
    
    private Properties properties;
    
    private DefaultAsyncServiceQueue asyncServiceQueue;
    
    private AsyncRpcResultMemCache asyncRpcResultcache;
    
    /**
     * @param properties
     */
    public DefaultAsyncServiceManager(Properties properties) {
        this.properties = properties;
        this.asyncServiceQueue = new DefaultAsyncServiceQueue(new AsyncServiceQueueOptions(this.properties));
        this.asyncRpcResultcache = new AsyncRpcResultMemCache(new AsyncRpcResultMemCacheOptions(this.properties));
        RpcEventCenter.getInstance().registerListener(this);
        
        RpcServiceRepository.getInstance()
                            .registerService(new RpcServiceMetadata(AsyncRpcResultRetriever.SERVICE_NAME,
                                                                    DefaultAsyncServiceManager.class,
                                                                    AsyncRpcResultRetriever.class,
                                                                    this,
                                                                    this));
    }
    
    /**
     * 
     */
    public boolean support(RpcEventObject eventObject) {
        return eventObject instanceof AsyncRpcRequestProcessedEventObject;
    }
    
    /**
     * 
     */
    public void handle(RpcEventObject eventObject) {
        AsyncRpcRequestProcessedEventObject asyncRpcRequestProcessedEventObject = (AsyncRpcRequestProcessedEventObject) eventObject;
        asyncServiceQueue.removeAsynServiceRequest(asyncRpcRequestProcessedEventObject.getAsynServiceRequest()
                                                                                      .getRequestId());
        asyncRpcResultcache.put(asyncRpcRequestProcessedEventObject.getAsynServiceRequest()
                                                                   .getRequestId(),
                                asyncRpcRequestProcessedEventObject.getAsyncRpcResult());
    }
    
    /**
     * @return
     */
    public int queuedSize() {
        return asyncServiceQueue.size();
    }
    
    /**
     * @return
     */
    public int completedSize() {
        return asyncRpcResultcache.size();
    }
    
    public AsyncRpcResult findById(String requestId) {
        AsyncRpcResult result = asyncServiceQueue.findById(requestId);
        if (result != null) {
            return result;
        }
        
        return asyncRpcResultcache.get(requestId);
    }
    
    public AsyncRpcResultCache getAsyncRpcResultCache() {
        return this.asyncRpcResultcache;
    }
    
    public AsyncServiceQueue getAsyncServiceQueue() {
        return this.asyncServiceQueue;
    }
    
    public void shutdown() {
        try {
            this.asyncRpcResultcache.shutdown();
        }
        catch (Exception e) {
            logger.error(e, e);
        }
        try {
            this.asyncServiceQueue.shutdown();
        }
        catch (Exception e) {
            logger.error(e, e);
        }
    }
    
}
